package com.ggb.readingtime.handler


import com.fasterxml.jackson.databind.ObjectMapper
import com.ggb.readingtime.constants.ALREADY_EXISTS
import com.ggb.readingtime.constants.UNKNOWN_ERROR
import com.ggb.readingtime.exception.BaseException
import com.ggb.readingtime.extension.log
import com.ggb.readingtime.model.Result

import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler
import org.springframework.dao.DuplicateKeyException
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.bind.support.WebExchangeBindException
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono

/**
 * 全局异常处理器，处理项目中抛出的业务异常
 */

@RestControllerAdvice
class GlobalExceptionHandler: ErrorWebExceptionHandler {


    override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono<Void> {
        val response = exchange.response
        response.headers.contentType = MediaType.APPLICATION_JSON
        response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR // 根据异常类型设置适当的状态码
        log.error("异常：{}",ex.message)
        val errorResponse = Result.error<String>("Internal Server Error")
        val dataBuffer = response.bufferFactory().wrap(ObjectMapper().writeValueAsBytes(errorResponse))

        return response.writeWith(Mono.just(dataBuffer))
    }
    /**
     * 捕获业务异常
     */
    @ExceptionHandler(BaseException::class)
    fun exceptionHandler(ex: BaseException, exchange: ServerWebExchange): Mono<Result<String>> {
        log.error("异常信息：{}", ex.message)
        return Mono.just(Result.error(ex.message ?: ""))

    }

    @ExceptionHandler(DuplicateKeyException::class)
    fun exceptionHandler(ex: DuplicateKeyException, exchange: ServerWebExchange): Mono<Result<String>> {
        val message = ex.mostSpecificCause.message
        if (message?.contains("Duplicate entry") == true) {
            val split = message.split(" ")
            val username = split[2]
            val msg = username + ALREADY_EXISTS
            return Mono.just(Result.error(msg))
        }
        return Mono.just(Result.error(UNKNOWN_ERROR))
    }

    @ExceptionHandler(WebExchangeBindException::class)
    fun handleValidationException(exception: WebExchangeBindException, exchange: ServerWebExchange): Mono<Result<String>> {
        val message = StringBuilder()
        exception.bindingResult.fieldErrors.forEach { fieldError ->
            message.append(fieldError.field).append(": ").append(fieldError.defaultMessage).append("; ")
        }
        return Mono.just(Result.error(message.toString()))
    }
}